package com.bianmaba.controllers.datacollection;

import com.bianmaba.beans.datacollection.ExecuteLog;
import com.bianmaba.beans.datacollection.TaskInstance;
import com.bianmaba.commons.bean.result.OperationResult;
import com.bianmaba.services.datacollection.CollectionTaskService;
import com.bianmaba.services.datacollection.ExecuteLogRecorder;
import com.bianmaba.services.datacollection.TaskInstanceService;
import com.bianmaba.services.datacollection.quartiz.QuartzTaskManager;
import com.bianmaba.spring.mvc.annotation.RequestResponseBodyConfig;
import io.swagger.annotations.Api;
import org.quartz.JobDataMap;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;

import java.util.Calendar;
import java.util.Map;


@Api(description = "JOB操作API")
@RestController
@RequestMapping(value = "datacollection/job")
public class JobController {
    private static Logger LOG = LoggerFactory.getLogger(JobController.class);
    @Autowired
    private QuartzTaskManager quartzTaskManager;
    @Autowired
    private TaskInstanceService taskInstanceService;
    @Autowired
    private CollectionTaskService collectionTaskService;
    @Autowired
    protected RestTemplate restTemplate;
    @Autowired
    protected ExecuteLogRecorder logWriter;

    @RequestResponseBodyConfig
    @RequestMapping("add")
    public boolean add(String name, String group, String classPath) throws ClassNotFoundException, SchedulerException {
        Class clazz = Class.forName(classPath);
        JobDataMap data = new JobDataMap();
        data.put("description", "add Job is running...");
        quartzTaskManager.addJob(clazz, name, group, data, true, true);
        return true;
    }

    @RequestResponseBodyConfig
    @RequestMapping("delete")
    public boolean delete(String name, String group) throws SchedulerException {
        quartzTaskManager.deleteJob(name, group);
        return true;
    }

    @RequestResponseBodyConfig
    @RequestMapping("trigger")
    public boolean trigger(String name, String group) {
        quartzTaskManager.triggerJob(name, group);
        return true;
    }

    @RequestMapping("schedule")
    public Trigger schedule(String name, String group, String cronExpression) throws ClassNotFoundException {
        Class clazz = Class.forName("com.bianmaba.jobs.DefaultJob");
        JobDataMap data = new JobDataMap();
        data.put("description", "scheduleJob is running...");

        return quartzTaskManager.scheduleJob(clazz, name, group, cronExpression, data);
    }

    @RequestResponseBodyConfig
    @RequestMapping("pause")
    public void pause(String name, String group) throws SchedulerException {
        quartzTaskManager.pauseJob(name, group);
    }

    @RequestResponseBodyConfig
    @RequestMapping("resume")
    public void resume(String name, String group) throws SchedulerException {
        quartzTaskManager.resumeJob(name, group);
    }

    @RequestResponseBodyConfig
    @RequestMapping("reschedule")
    public Trigger reschedule(String name, String group, String cronExpression) throws ClassNotFoundException {
        return quartzTaskManager.rescheduleJob(name, group, "0/5 * * * * ?");
    }

    @RequestResponseBodyConfig
    @RequestMapping("stop_job")
    public OperationResult stopJob(String taskInstanceId) throws InterruptedException {
        TaskInstance taskInstance = taskInstanceService.findOne(taskInstanceId);

        String url = taskInstance.getCollectionTask().getCollectionInterface().getBaseUrl() + "stop";
        OperationResult<Integer> result = sendStopRequest(url, taskInstanceId);
        if (!result.isSuccess() && result.getData() != null) {
            taskInstanceService.updateStatus(taskInstanceId, result.getData());
        }
        return result;
    }

    protected OperationResult<Integer> sendStopRequest(String url, String taskInstanceId) throws InterruptedException {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);

        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("taskInstanceId", taskInstanceId);

        HttpEntity<Map> entity = new HttpEntity(map, headers);

        ResponseEntity<OperationResult> responseEntity = null;
        try {
            responseEntity = restTemplate.postForEntity(url, entity, OperationResult.class);
        } catch (HttpClientErrorException e) {
            int code = e.getRawStatusCode();
            String error = e.getLocalizedMessage();
            if (code == 401) {
                error = "停止采集请求失败，目标地址未经授权访问或由于凭据无效被拒绝：";
            } else if (code == 403) {
                error = "停止采集请求失败，目标地址未经授权，请联系管理员：";
            } else if (code == 404) {
                error = "停止采集请求失败，目标地址不存在请联系管理员：";
            } else if (code == 405) {
                error = "停止采集请求失败，请求方式（Method）不受支持，请联系管理员：";
            } else if (code == 500) {
                error = "停止采集请求失败，采集服务出现内部错误，请联系管理员：";
            }
            error = error + String.format("【statusCode=%d,URL=%s,parameters=%s】", code, url, map.toString());
            LOG.error(error, e);
            logWriter.put(ExecuteLog.of(taskInstanceId, error, Calendar.getInstance().getTime()));
            return OperationResult.of(false).setResult(error);
        } catch (ResourceAccessException e) {
            String error = "停止采集请求失败，服务器未开启，请联系管理员：";
            error = error + String.format("【URL=%s,parameters=%s】", url, map.toString());
            LOG.error(error, e);
            logWriter.put(ExecuteLog.of(taskInstanceId, error, Calendar.getInstance().getTime()));
            return OperationResult.of(false).setResult(error);
        } catch (Exception e) {
            String error = "停止采集请求失败，停止采集出现未知异常，请联系管理员：";
            error = error + String.format("【URL=%s,parameters=%s】", url, map.toString());
            LOG.error(error, e);
            logWriter.put(ExecuteLog.of(taskInstanceId, error, Calendar.getInstance().getTime()));
            return OperationResult.of(false).setResult(error);
        }
        OperationResult<Integer> result = responseEntity.getBody();
        if (result.isSuccess()) {
            logWriter.put(ExecuteLog.of(taskInstanceId, result.getResult(), Calendar.getInstance().getTime()));
        }
        return result;
    }


}
